#include <iostream>
#include <cstring>

#include <pthread.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <functional>

#include "ThreadPool.hpp"
#include "InitAddr.hpp"
#include "Log.hpp"
#include "Comm.hpp"

using namespace ThreadPoolModule;
using namespace LogModule;

const static int gpost = 8081;

#define BACKLOG 8

using handler_t = std::function<std::string(std::string)>;

class TcpServer
{
	using task_t = std::function<void()>;
	struct ThreadDate
	{
		int sockfd;
		TcpServer *self;
	};
public:
	TcpServer(handler_t handler,int post = gpost) : _handler(handler),_post(post), _IsRunning(false)
	{
	}
	void InitServer()
	{
		// 创建套接字
		_listensockfd = ::socket(AF_INET, SOCK_STREAM, 0);
		if (_listensockfd < 0)
		{
			LOG(LogLevel::FATAL) << "socket error";
			Die(SOCKET_ERR);
		}
		LOG(LogLevel::INFO) << "socket create success, sockfd is : " << _listensockfd;
		struct sockaddr_in local;
		memset(&local, 0, sizeof(local));
		local.sin_family = AF_INET;
		local.sin_port = ::htons(gpost);
		local.sin_addr.s_addr = INADDR_ANY;

		// bind
		int n = ::bind(_listensockfd, CONV(&local), sizeof(local));
		if (n < 0)
		{
			LOG(LogLevel::FATAL) << "bind error";
			Die(BIND_ERR);
		}
		LOG(LogLevel::INFO) << "bind success, sockfd is : " << _listensockfd;
		// 3. cs,tcp是面向连接的，就要求tcp随时随地等待被连接
		// tcp 需要将socket设置成为监听状态
		n = ::listen(_listensockfd, BACKLOG);
		if (n < 0)
		{
			LOG(LogLevel::FATAL) << "listen error";
			Die(LISTEN_ERR);
		}
		LOG(LogLevel::INFO) << "listen success, sockfd is : " << _listensockfd;
		// ::signal(SIGCHLD, SIG_IGN); // 忽略子进程结束信号 不用等待子进程结束
	}
	void HandlerRequest(int sockfd)
	{
		LOG(LogLevel::INFO) << "HandlerRequest, sockfd is : " << sockfd;
		char buffer[1024];
		while (true)
		{
			// ssize_t n = ::read(sockfd, buffer, sizeof(buffer) - 1);
			ssize_t n = ::recv(sockfd, buffer, sizeof(buffer) - 1,0);
			if (n > 0)
			{
				LOG(LogLevel::INFO)  << buffer;

				buffer[n] = 0;
				// std::string echo_str = "server echo# ";
				// echo_str += buffer;

				std::string echo_str = _handler(buffer);
				// ::write(sockfd, echo_str.c_str(), echo_str.size());
				::send(sockfd, echo_str.c_str(), echo_str.size(),0);
			}
			else if(n == 0)
			{
				// 客户端退出
				// read 如果读取返回值是0，表示client退出
                LOG(LogLevel::INFO) << "client quit: " << sockfd;
                break;
			}
			else
			{
				break;
			}
		}
		::close(sockfd);
	}
	static void *ThreadEntry(void *arg)
	{
		// 分离线程,防止线程退出导致程序退出，主线程不关心子线程的退出
		pthread_detach(pthread_self());
		ThreadDate *s = (ThreadDate *)arg;
		
		s->self->HandlerRequest(s->sockfd);
		return nullptr;
	}
	void Start()
	{
		_IsRunning = true;
		while (true)
		{
			// 不能直接读取数据
			// 1. 获取新连接
			struct sockaddr_in pree;
			socklen_t preelen = sizeof(pree);
			int sockfd = ::accept(_listensockfd, CONV(&pree), &preelen);
			if (sockfd < 0)
			{
				// 没链接上继续链接
				LOG(LogLevel::WARNING) << "accept error: " << strerror(errno);
				continue;
			}
			// 获取链接成功
			LOG(LogLevel::INFO) << "accept success, sockfd is : " << sockfd;
			Inetaddr addr(pree);
			LOG(LogLevel::INFO) << "client info : " << addr.addr();

			//// version-0
			// HandlerRequest(sockfd);
//---------------------------------------------------------------
			// // version-1 多线程版本
			// pid_t n = ::fork();
			// if (n == 0)
			// {
			// 	// 子进程
			// 	// 关闭不需要的套接字
			// 	::close(_listensockfd);
			// 	if (fork() == 0)
			// 	{
			// 		// 孙子进程
			// 		HandlerRequest(sockfd);
			// 	}
			// 	// 子进程结束，孙子进程变成孤儿进程，有1领养
			// 	exit(0);
			// }
			// // 父进程
			// ::close(sockfd);
			// pid_t rid = ::waitpid(n, nullptr, 0);
			// if (rid < 0)
			// {
			// 	LOG(LogLevel::WARNING) << "waitpid error: " << strerror(errno);
			// }
//---------------------------------------------------------------------
			// // version-2 多线程版本
			// pthread_t pid;
			// ThreadDate *data = new ThreadDate;
			// data->sockfd = sockfd;
			// data->self = this;
			// int n = pthread_create(&pid,nullptr,ThreadEntry,(void *)data);
//---------------------------------------------------------------------
			// version-3：线程池版本 比较适合处理短任务，或者是用户量少的情况
			task_t f = std::bind(&TcpServer::HandlerRequest,this,sockfd);
			ThreadPool<task_t>::getInstance()->Equeue(f);
		}
		_IsRunning = false;
	}
	~TcpServer()
	{
	}

private:
	int _listensockfd;
	uint16_t _post;
	bool _IsRunning;

	handler_t _handler;
};